#pragma once
#include "../common/net.hpp"
#include "../common/message.hpp"
#include <future>
#include <functional>


namespace rpc
{
    namespace client
    {
        class Requestor
        {
        public:
            using ptr = std::shared_ptr<Requestor>;
            using RequestCallback = std::function<void(const BaseMessage::ptr&)>;
            using AsyncResponse = std::future<BaseMessage::ptr>;
            struct RequestDescribe
            {
                using ptr = std::shared_ptr<RequestDescribe>;
                BaseMessage::ptr request;
                Rtype rtype;//请求模式，同步还是异步
                std::promise<BaseMessage::ptr> response;
                RequestCallback callback;
            };

            void onResponse(const BaseConnection::ptr& conn,BaseMessage::ptr& msg)
            {
                std::string rid = msg->id();
                RequestDescribe::ptr req = getDescribe(rid);
                if(req.get() == nullptr)
                {
                    ELOG("收到响应 - %s，但是未找到对应的请求描述！", rid.c_str());
                    return;
                }
                if(req->rtype == Rtype::REQ_ASYNC)
                {
                    req->response.set_value(msg);
                }
                else if(req->rtype == Rtype::REQ_CALLBACK)
                {
                    if(req->callback) req->callback(msg);
                }
                else
                {
                    ELOG("请求类型未知！！");
                }
                delDescribe(rid);
            }
            bool send(const BaseConnection::ptr& conn,const BaseMessage::ptr& req,AsyncResponse& rsp)
            {
                RequestDescribe::ptr rdp = newDescribe(req,Rtype::REQ_ASYNC);
                if(rdp.get() == nullptr)
                {
                    ELOG("构造请求描述对象失败！");
                    return false;
                }
                conn->send(req);
                rsp = rdp->response.get_future();
                return true;
            }
            bool send(const BaseConnection::ptr& conn,const BaseMessage::ptr& req,BaseMessage::ptr& rsp)
            {
                AsyncResponse rsp_futrue;
                bool ret = send(conn,req,rsp_futrue);
                if(ret == false)
                {
                    ELOG("获取future对象失败");
                    return false;
                }
                rsp = rsp_futrue.get();
                return true;
            }
            bool send(const BaseConnection::ptr& conn,const BaseMessage::ptr& req, const RequestCallback& cb)
            {
                RequestDescribe::ptr rdp = newDescribe(req,Rtype::REQ_CALLBACK,cb);
                if(rdp.get() == nullptr)
                {
                    ELOG("构造请求描述对象失败！");
                    return false;
                }
                conn->send(req);
                return true;
            }
        private:
            RequestDescribe::ptr newDescribe(const BaseMessage::ptr& req,Rtype rtype,const RequestCallback &cb = RequestCallback())
            {
                std::unique_lock<std::mutex> lock(_mtx);
                RequestDescribe::ptr rdp = std::make_shared<RequestDescribe>();
                rdp->request = req;
                rdp->rtype = rtype;
                
                if(rtype == Rtype::REQ_CALLBACK && cb)
                {
                    rdp->callback = cb;
                }
                _request_desc.insert(std::make_pair(req->id(),rdp));
                return rdp;
            }
            RequestDescribe::ptr getDescribe(const std::string& rid)
            {
                std::unique_lock<std::mutex> lock(_mtx);
                auto it = _request_desc.find(rid);
                if(it == _request_desc.end())
                {
                    return RequestDescribe::ptr();
                }
                return it->second;
            }
            void delDescribe(const std::string &rid) 
            {
                std::unique_lock<std::mutex> lock(_mtx);
                _request_desc.erase(rid);
            }
        private:
            std::mutex _mtx;
            std::unordered_map<std::string,RequestDescribe::ptr> _request_desc;//id和请求描述的映射关系
        };
    }
}